#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sqlite3.h>
#include <time.h>
#include "module.h"

#define SQL_LEN 1024
#define DATABASE "StaffMS.db"

void do_connected(int socketfd, int client_sock, struct sockaddr_in *clientaddr, sqlite3 *db);
void do_register(int socketfd, sqlite3 *db);
int do_login(int socketfd, sqlite3 *db);
int do_create_account(int socketfd, sqlite3 *db);
void do_create_user_account(int socketfd, sqlite3 *db);
void cerate_account(sqlite3 *db, msg_t *msg, user_obj_t *user, role_obj_t *role);
void send_func_list(int socketfd, sqlite3 *db, user_obj_t *user, func_obj_t *parent_func);
int primary_key_callback(void *arg, int column, char **value, char **name);
int count_callback(void *arg, int column, char **value, char **name);
void get_account_list(int socketfd, sqlite3 *db);
void delete_account(int socketfd, sqlite3 *db);

int main(int argc, const char *argv[])
{
	if(3 != argc){
		printf("cmd + ip + port\n");
		exit(1);
	}
	sqlite3 *db;
	char *errmsg;
	// 检查数据库文件是否存在
	struct stat db_stat;
	stat(DATABASE, &db_stat);
	if(!S_ISREG(db_stat.st_mode)){
		printf("Please create database!!!\n");
		exit(1);
	}
	//打开数据库
	if(SQLITE_OK != sqlite3_open(DATABASE, &db)){
		printf("%s\n", sqlite3_errmsg(db));
		exit(1);
	}else{
		printf("database open done!!!\n");
	}
	//创建服务端socket
	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == socketfd){
		perror("fail to socket");
		exit(1);
	}
	//初始化服务端socket的地址信息
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	//socket绑定到指定地址
	int ret = bind(socketfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
	if(-1 == ret){
		perror("fail to bind!!!");
		exit(1);
	}
	//开始监听
	if(-1 == listen(socketfd, 5)){
		perror("fail to listen!!!");
		exit(1);
	}

	//忽略结束的子进程
	signal(SIGCHLD, SIG_IGN);

	//连接上的客户端
	struct sockaddr_in clientaddr;
	int clientaddr_len = sizeof(clientaddr);

	//传递的信息结构体

	while(1){
		//接收客户端连接
		int client_sock = accept(socketfd, (struct sockaddr *)&clientaddr, &clientaddr_len);
		if(-1 == client_sock){
			perror("fail to accept!!!");
			continue;
		}

		printf("client %s:%d connected!!!\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
		//创建子进程去处理新连接的客户端
		pid_t pid = fork();
		if(pid == 0){
			do_connected(socketfd, client_sock, &clientaddr, db);
		}
	}

	close(socketfd);
	return 0;
}

void do_connected(int socketfd, int client_sock, struct sockaddr_in * clientaddr, sqlite3 *db){

	int read_count;
	while(1){
		msg_t msg;
		read_count = read(client_sock, &msg, sizeof(msg_t));
		if(-1 == read_count){
			printf("fail to read msg from client %s:%d\n", inet_ntoa(clientaddr->sin_addr), ntohs(clientaddr->sin_port));
			break;
		}
		if(0 == read_count){
			printf("client %s:%d closed connect !!!\n", inet_ntoa(clientaddr->sin_addr), ntohs(clientaddr->sin_port));
			break;
		}
		printf("opt:%c\n", msg.opt_type);

		switch(msg.opt_type){
			case OPT_TYPE_REGISTER:
				do_register(client_sock, db);
				break;
			case OPT_TYPE_LOGIN:
				do_login(client_sock, db);
				break;
			case FUNC_CREATE_ACCOUNT:
				do_create_account(client_sock, db);
				break;
			case FUNC_CREATE_ADMIN_ACCOUNT:
			case FUNC_CREATE_USER_ACCOUNT:
				do_create_user_account(client_sock, db);
				break;
			case FUNC_DELETE_ACCOUNT:
			case FUNC_EDITE_ACCOUNT:
				get_account_list(client_sock, db);
				break;
			case OPT_UPDATE_PASSWORD:
				update_passwd(client_sock, db);
			case OPT_DELETE_ACCOUNT:
				delete_account(client_sock, db);
				break;
			default:
				printf("error option!!! client %s:%d\n", inet_ntoa(clientaddr->sin_addr), ntohs(clientaddr->sin_port));
		}
	}
	close(client_sock);
	exit(0);

	return;
}

void delete_account(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client!!!\n");
		return;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	char *errmsg;
	char sql[SQL_LEN] = {};
	sprintf(sql, "delete from user where id = %d", user.id);
	printf("sql : %s\n", sql);

	int write_count = 0;
	msg_t msg;
	msg.opt_result = 0;
	if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg)){
		printf("%s\n", errmsg);
		msg.opt_result = -2;
	}else{
		sprintf(sql, "delete from user_role where user_id = %d", user.id);
		printf("sql : %s\n", sql);
		if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg)){
			printf("%s\n", errmsg);
			msg.opt_result = -2;
		}else{
			msg.opt_result = 0;
		}
	}

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send to client!!!\n");
	}

	return;
}
void update_passwd(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client!!!\n");
		return;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	char *errmsg;
	char sql[SQL_LEN] = {};
	sprintf(sql, "update user set passwd = '%s' where id = %d", user.passwd, user.id);
	printf("sql : %s\n", sql);

	int write_count = 0;
	msg_t msg;
	msg.opt_result = 0;
	if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg)){
		printf("%s\n", errmsg);
		msg.opt_result = -2;
	}else{
		msg.opt_result = 0;
	}

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send to client!!!\n");
	}

	return;
}

void get_account_list(int socketfd, sqlite3 *db){
	char *errmsg;
	char sql[SQL_LEN] = {};

	char **result;
	int rows = 0;
	int cols = 0;
	
	sprintf(sql, "select * from user where id != 1");
	printf("sql : %s\n", sql);

	if(sqlite3_get_table(db, sql, &result, &rows, &cols, &errmsg) != SQLITE_OK){
		printf("%s\n", errmsg);
	}else{
		int write_count = 0;

		write_count = write(socketfd, &rows, sizeof(int));
		if(-1 == write_count){
			printf("fail to send to client!!!\n");
		}else{
			user_obj_t user_obj;
			int row_index = 0;
			int col_index = 0;
			printf("%s\t%s\t%s\n", result[0], result[1], result[2]);
			for(row_index = 1; row_index < rows + 1; row_index++){

				user_obj.id = atoi(result[row_index * cols + 0]);
				strncpy(user_obj.username, result[row_index * cols + 1], NAME_SIZE - 1);
				strncpy(user_obj.passwd, result[row_index * cols + 2], PASSWD_SIZE - 1);

				printf("%d\t%s\t%s\n", user_obj.id, user_obj.username, user_obj.passwd);

				write_count = write(socketfd, &user_obj, sizeof(user_obj_t));
				if(write_count == -1){
					printf("fail to send to client!!!\n");
				}
			}
			printf("finished to send user list!!!\n");
		}
	}
}

void do_register(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client!!!\n");
		return;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	role_obj_t role;
	role.id = ROLE_USER_ID;

	int write_count = 0;
	msg_t msg;
	msg.opt_result = 0;
	
	create_account(db, &msg, &user, &role);
	
	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send to client!!!\n");
	}

	return;
}

int do_login(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client\n");
		return -1;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return -1;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	char *errmsg;
	char sql[SQL_LEN] = {};
	sprintf(sql, "select count(1) from user where username = '%s' and passwd = '%s'", user.username, user.passwd);
	printf("sql : %s\n", sql);
	
	int write_count;
	int count = 0;
	msg_t msg;
	msg.opt_result = 0;

	if(SQLITE_OK != sqlite3_exec(db, sql, count_callback, &count, &errmsg)){
		printf("%s\n", errmsg);
		msg.opt_result = -2;
	}else{
		if(1 == count){
			msg.opt_result = 0;
		}else if(0 == count){
			msg.opt_result = -1;
		}else{
			msg.opt_result = -2;
		}
	}

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send to client!!!\n");
		return -1;
	}else{
		int user_id = 0;
		sprintf(sql, "select id from user where username = '%s'", user.username);
		printf("sql : %s\n", sql);
		if(SQLITE_OK != sqlite3_exec(db, sql, primary_key_callback, &user_id, &errmsg)){
			msg.opt_result = -2;
			printf("fail to get user primary key!!!\n");
		}else{
			user.id = user_id;
			write_count = write(socketfd, &user, sizeof(user_obj_t));
			if(-1 == write_count){
				perror("fail to send user to client!!!\n");
				return -1;
			}
		}

		func_obj_t func_obj;
		func_obj.id = FUNC_LOGIN;
		//发送菜单
		send_func_list(socketfd, db, &user, &func_obj);
	}

	return 0;
}

int do_create_account(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client\n");
		return -1;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return -1;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	func_obj_t func_obj;
	read_count = read(socketfd, &func_obj, sizeof(func_obj_t));
	if(-1 == read_count){
		printf("fail to read func_obj from client\n");
		return -1;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return -1;
	}

	printf("funcId:%d funcName:%s funcDesc:%s funcParebt:%d\n", func_obj.id, func_obj.func_name, func_obj.func_desc, func_obj.func_parent);
	//发送菜单
	send_func_list(socketfd, db, &user, &func_obj);
	
	return 0;
}

void do_create_user_account(int socketfd, sqlite3 *db){
	user_obj_t user;
	int read_count = 0;
	read_count = read(socketfd, &user, sizeof(user_obj_t));
	if(-1 == read_count){
		printf("fail to read user from client!!!\n");
		return;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return;
	}

	printf("username:%s passwd:%s\n", user.username, user.passwd);

	role_obj_t role;
	read_count = read(socketfd, &role, sizeof(role_obj_t));
	if(-1 == read_count){
		printf("fail to read role from client!!!\n");
		return;
	}
	if(0 == read_count){
		printf("client closed connect !!!\n");
		return;
	}

	printf("roleId : %d\n", role.id);

	int write_count = 0;
	msg_t msg;
	msg.opt_result = 0;
	
	create_account(db, &msg, &user, &role);
	
	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send to client!!!\n");
	}

	return;

}

void create_account(sqlite3 *db, msg_t *msg, user_obj_t *user, role_obj_t *role){

	char *errmsg;
	char sql[SQL_LEN] = {};
	sprintf(sql, "select count(1) from user where username = '%s'", user->username);
	printf("sql : %s\n", sql);

	int write_count = 0;
	int count = 0;
	msg->opt_result = 0;
	if(SQLITE_OK != sqlite3_exec(db, sql, count_callback, &count, &errmsg)){
		printf("%s\n", errmsg);
		msg->opt_result = -2;
	}else{
		if(0 != count){
			msg->opt_result = -1;
		}else{
			sprintf(sql, "insert into user(username, passwd) values('%s', '%s')", user->username, user->passwd);
			printf("sql : %s\n", sql);
			if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg)){
				msg->opt_result = -2;
				printf("fail to insert into user\n");
			}else{
				int user_id = 0;
				sprintf(sql, "select id from user where username = '%s'", user->username);
				printf("sql : %s\n", sql);
				if(SQLITE_OK != sqlite3_exec(db, sql, primary_key_callback, &user_id, &errmsg)){
					msg->opt_result = -2;
					printf("fail to get user primary key!!!\n");
				}else{
					//注册用户默认是普通用户权限
					sprintf(sql, "insert into user_role(user_id, role_id) values(%d, %d)", user_id, role->id);
					printf("sql : %s\n", sql);
					if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg)){
						msg->opt_result = -2;
						printf("fail to insert into user_role!!!\n");
					}
				}
			}
		}
	}
	return;
}

void send_func_list(int socketfd, sqlite3 *db, user_obj_t *user, func_obj_t *parent_func){
	char *errmsg;
	char sql[SQL_LEN] = {};

	int is_admin = 0;

	char **result;
	int rows = 0;
	int cols = 0;
	sprintf(sql, "select user_role.role_id from user_role where user_id = %d", user->id);
	printf("sql : %s\n", sql);
	if(sqlite3_get_table(db, sql, &result, &rows, &cols, &errmsg) != SQLITE_OK){
		printf("%s\n", errmsg);
		return;
	}else{
		int row_index = 0;
		for(row_index = 1; row_index < rows + 1; row_index++){
			if(ROLE_ADMIN_ID == atoi(result[row_index * cols + 0])){
				is_admin = 1;
				break;
			}
		}
	}

	//发送菜单
	if(is_admin){
		sprintf(sql, "select func.id, func.func_name, func.func_desc, func.func_parent from func where func_parent = %d", parent_func->id);
	}else{
		sprintf(sql, "select func.id, func.func_name, func.func_desc, func.func_parent from user left join user_role on user_role.user_id = user.id left join role_permission on user_role.role_id = role_permission.role_id left join func on role_permission.func_id = func.id where user.id = %d and func_parent = %d", user->id, parent_func->id);
	}
	printf("sql : %s\n", sql);
	if(sqlite3_get_table(db, sql, &result, &rows, &cols, &errmsg) != SQLITE_OK){
		printf("%s\n", errmsg);
	}else{
		int write_count = 0;

		write_count = write(socketfd, &rows, sizeof(int));
		if(-1 == write_count){
			printf("fail to send to client!!!\n");
		}else{
			func_obj_t func_obj;
			int row_index = 0;
			int col_index = 0;
			printf("%s\t%s\t%s\t%s\n", result[0], result[1], result[2], result[3]);
			for(row_index = 1; row_index < rows + 1; row_index++){
				bzero(func_obj.func_desc, sizeof(func_obj.func_desc));

				func_obj.id = atoi(result[row_index * cols + 0]);
				strncpy(func_obj.func_name, result[row_index * cols + 1], FUNC_NAME_SIZE - 1);
				strncpy(func_obj.func_desc, result[row_index * cols + 2], FUNC_DESC_SIZE - 1);
				func_obj.func_parent = atoi(result[row_index * cols + 3]);

				printf("%d\t%s\t%s\t%d\n", func_obj.id, func_obj.func_name, func_obj.func_desc, func_obj.func_parent);

				write_count = write(socketfd, &func_obj, sizeof(func_obj_t));
				if(write_count == -1){
					printf("fail to send to client!!!\n");
				}
			}
			printf("finished to send func info!!!\n");
		}
	}

	return;
}

int primary_key_callback(void *arg, int column, char **value, char **name){
	(*(int *)arg) = atoi(value[0]);
	return 0;
}


int count_callback(void *arg, int column, char **value, char **name){
	(*(int *)arg) = atoi(value[0]);
	return 0;
}


